package dal

import (
	"Metro/config"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/bsm/redislock"
	"github.com/redis/go-redis/v9"
	"jialiking.com/gaogang/common/utils"
	"math/rand"
	"time"
)

var RedisClient *redis.Client
var random *rand.Rand

func init() {
	source := rand.NewSource(time.Now().UnixNano())
	random = rand.New(source)
	RedisClient = redis.NewClient(&redis.Options{
		Addr: config.RedisAddr,
	})
}

type FuncWithLock func()

func (f FuncWithLock) WithRedisLock(key string) {
	ctx := context.Background()
	locker := redislock.New(RedisClient)
	lock, e := locker.Obtain(ctx, key, 5*time.Second, &redislock.Options{
		RetryStrategy: redislock.LinearBackoff(100 * time.Millisecond),
	})
	if errors.Is(e, redislock.ErrNotObtained) {
		utils.ErrorLog("Could not obtain gateway lock!")
		return
	} else if e != nil {
		utils.ErrorLog(e.Error())
		return
	}
	f()
	defer func() {
		e = lock.Release(ctx)
		if e != nil {
			utils.ErrorLog(e.Error())
		}
	}()

}

func Set(key string, value any, timeout time.Duration) error {
	data, e := json.Marshal(value)
	if e != nil {
		utils.ErrorLog("json 序列化失败: %s", e)
	} else {
		e = RedisClient.Set(context.Background(), fmt.Sprintf("%s%s", config.RedisKeyPrefix, key), data, timeout).Err()
		if e != nil {
			utils.ErrorLog(e)
		}
	}
	return e
}

func Get(key string, result any) error {
	data, e := RedisClient.Get(context.Background(), fmt.Sprintf("%s%s", config.RedisKeyPrefix, key)).Bytes()
	if e != nil {
		return e
	} else {
		e = json.Unmarshal(data, result)
		if e != nil {
			return e
		}
		return nil
	}
}

func HSet(key string, field string, value int64) error {
	e := RedisClient.HSet(context.Background(), key, fmt.Sprintf("%s%s", config.RedisKeyPrefix, field), value).Err()
	if e != nil {
		utils.ErrorLog(e)
	}
	return e
}

func HDel(key string, field string) error {
	e := RedisClient.HDel(context.Background(), key, fmt.Sprintf("%s%s", config.RedisKeyPrefix, field)).Err()
	if e != nil {
		utils.ErrorLog(e)
	}
	return e
}

func SetNX(key string, value any, timeout time.Duration) error {
	data, e := json.Marshal(value)
	if e != nil {
		utils.ErrorLog("json 序列化失败: %s", e)
	} else {
		e = RedisClient.SetNX(context.Background(), fmt.Sprintf("%s%s", config.RedisKeyPrefix, key), data, timeout).Err()
		if e != nil {
			utils.ErrorLog(e.Error())
		}
	}
	return e
}

func GetUniqueID() int64 {
	timestamp := time.Now().Unix()
	err := SetNX(fmt.Sprintf("%d", timestamp), 0, time.Second)
	if err != nil {
		utils.ErrorLog("GetUniqueID: %s", err.Error())
		return random.Int63()
	}
	incr, err := RedisClient.Incr(context.Background(), fmt.Sprintf("%d", timestamp)).Result()
	if err != nil {
		utils.ErrorLog("GetUniqueID Incr: %s", err.Error())
		return random.Int63()
	}
	return (timestamp&0xffffffff)<<16 | (incr & 0xffff)
}
